#include "vrpn_Generic_server_object.h"
#include "vrpn_ForwarderController.h"

void Usage (const char * s)
{
  fprintf(stderr,"Usage: %s [-f filename] [-warn] [-v] [port] [-q]\n",s);
  fprintf(stderr,"       [-client machinename port] [-millisleep n]\n");
  fprintf(stderr,"       [-NIC name] [-li filename] [-lo filename]\n");
  fprintf(stderr,"       -f: Full path to config file (default vrpn.cfg).\n");
  fprintf(stderr,"       -millisleep: Sleep n milliseconds each loop cycle\n"); 
  fprintf(stderr,"                    (if no option is specified, the Windows architecture\n");
  fprintf(stderr,"                     will free the rest of its time slice on each loop\n");
  fprintf(stderr,"                     but leave the processes available to be run immediately;\n");
  fprintf(stderr,"                     a 1ms sleep is the default on all other architectures).\n");
  fprintf(stderr,"                    -millisleep 0 is recommended when using this server and\n"); 
  fprintf(stderr,"                     a client on the same uniprocessor CPU Win32 PC.\n");
  fprintf(stderr,"                    -millisleep -1 will cause the server process to use the\n"); 
  fprintf(stderr,"                     whole CPU on any uniprocessor machine.\n");
  fprintf(stderr,"       -warn: Only warn on errors (default is to bail).\n");
  fprintf(stderr,"       -v: Verbose.\n");
  fprintf(stderr,"       -q: Quit when last connection is dropped.\n");
  fprintf(stderr,"       -client: Where server connects when it starts up.\n");
  fprintf(stderr,"       -NIC: Use NIC with given IP address or DNS name.\n");
  fprintf(stderr,"       -li: Log incoming messages to given filename.\n");
  fprintf(stderr,"       -lo: Log outgoing messages to given filename.\n");
  exit(0);
}

static	int	done = 0;	// Done and should exit?

vrpn_Connection * connection;
vrpn_Generic_Server_Object  *generic_server = NULL;

static char * g_NICname = NULL;

static const char * g_inLogName = NULL;
static const char * g_outLogName = NULL;

// TCH October 1998
// Use Forwarder as remote-controlled multiple connections.
vrpn_Forwarder_Server * forwarderServer;

bool  verbose = true;

void shutDown (void)
{
  if (generic_server) { delete generic_server; generic_server = NULL; }
  if (connection) { delete connection; connection = NULL; }
  if (verbose) { fprintf(stderr,"Deleted server and connection, Exiting.\n"); }
  exit(0);
}

int VRPN_CALLBACK handle_dlc (void *, vrpn_HANDLERPARAM p)
{
    shutDown();
    return 0;
}

// install a signal handler to shut down the trackers and buttons
#ifndef WIN32
#include <signal.h>
//#ifdef sgi
//void sighandler( ... )
//#else
void sighandler (int)
//#endif
{
	done = 1;
}
#endif


int main (int argc, char * argv[])
{
  char	* config_file_name = "vrpn.cfg";
  char 	* client_name = NULL;
  int	client_port;
  bool	bail_on_error = true;
  int	auto_quit = 0;
  int	realparams = 0;
  int	i;
  int	port = vrpn_DEFAULT_LISTEN_PORT_NO;
#ifdef	_WIN32
  // On Windows, the millisleep with 0 option frees up the CPU time slice for other jobs
  // but does not sleep for a specific time.  On Unix, this returns immediately and does
  // not do anything but waste cycles.
  int	milli_sleep_time = 0;		// How long to sleep each iteration (default: free the timeslice but be runnable again immediately)
#else
  int	milli_sleep_time = 1;		// How long to sleep each iteration (default: 1ms)
#endif
#ifdef WIN32
  WSADATA wsaData; 
  int status;
  if ((status = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0) {
    fprintf(stderr, "WSAStartup failed with %d\n", status);
    return(1);
  }
#else
#ifdef sgi
  sigset( SIGINT, sighandler );
  sigset( SIGKILL, sighandler );
  sigset( SIGTERM, sighandler );
  sigset( SIGPIPE, sighandler );
#else
  signal( SIGINT, sighandler );
  signal( SIGKILL, sighandler );
  signal( SIGTERM, sighandler );
  signal( SIGPIPE, sighandler );
#endif // not sgi
#endif // not WIN32

  // Parse the command line
  i = 1;
  while (i < argc) {
    if (!strcmp(argv[i], "-f")) {		// Specify config-file name
      if (++i > argc) { Usage(argv[0]); }
      config_file_name = argv[i];
    } else if (!strcmp(argv[i], "-millisleep")) {	// How long to sleep each loop?
      if (++i > argc) { Usage(argv[0]); }
      milli_sleep_time = atoi(argv[i]);
    } else if (!strcmp(argv[i], "-warn")) {// Don't bail on errors
      bail_on_error = false;
    } else if (!strcmp(argv[i], "-v")) {	// Verbose
      verbose = true;
    } else if (!strcmp(argv[i], "-q")) {  // quit on dropped last con
      auto_quit = 1;
    } else if (!strcmp(argv[i], "-client")) { // specify a waiting client
      if (++i > argc) { Usage(argv[0]); }
      client_name = argv[i];
      if (++i > argc) { Usage(argv[0]); }
      client_port = atoi(argv[i]);
    } else if (!strcmp(argv[i], "-NIC")) { // specify a network interface
      if (++i > argc) { Usage(argv[0]); }
      if (verbose) { fprintf(stderr, "Listening on network interface card %s.\n", argv[i]); }
      g_NICname = argv[i];
    } else if (!strcmp(argv[i], "-li")) { // specify server-side logging
      if (++i > argc) { Usage(argv[0]); }
      if (verbose) { fprintf(stderr, "Incoming logfile name %s.\n", argv[i]); }
      g_inLogName = argv[i];
    } else if (!strcmp(argv[i], "-lo")) { // specify server-side logging
      g_outLogName = argv[i];
      if (++i > argc) { Usage(argv[0]); }
      if (verbose) { fprintf(stderr, "Outgoing logfile name %s.\n", argv[i]); }
    } else if (argv[i][0] == '-') {	// Unknown flag
      Usage(argv[0]);
    } else switch (realparams) {		// Non-flag parameters
      case 0:
	  port = atoi(argv[i]);
	  realparams++;
	  break;
      default:
	  Usage(argv[0]);
    }
    i++;
  }

  // Need to have a global pointer to it so we can shut it down
  // in the signal handler (so we can close any open logfiles.)
  //vrpn_Synchronized_Connection	connection;
  connection = new vrpn_Connection
       (port, g_inLogName, g_outLogName, g_NICname);

  // Create the generic server object and make sure it is doing okay.
  generic_server = new vrpn_Generic_Server_Object(connection, config_file_name, port, verbose, bail_on_error);
  if ( (generic_server == NULL) || !generic_server->doing_okay() ) {
    fprintf(stderr,"Could not start generic server, exiting\n");
    shutDown();
  }

  // Open the Forwarder Server
  forwarderServer = new vrpn_Forwarder_Server (connection);

  // If we're set to auto-quit, then register a handler for the last connection
  // dropped that will cause a callback which will exit.
  if (auto_quit) {
    int dlc_m_id = connection->register_message_type(
			    vrpn_dropped_last_connection);
    connection->register_handler(dlc_m_id, handle_dlc, NULL);
  }

  if (client_name) {
    if (verbose) {
      fprintf(stderr, "vrpn_serv: connecting to client: %s:%d\n",
	  client_name, client_port);
    }
    if (connection->connect_to_client(client_name, client_port)){
	fprintf(stderr, "server: could not connect to client %s:%d\n",
		client_name, client_port);
	shutDown();
    }
  }

  // ********************************************************************
  // **                                                                **
  // **                MAIN LOOP                                       **
  // **                                                                **
  // ********************************************************************
  while (!done) {
    // Let the generic object server do its thing.
    if (generic_server) {
      generic_server->mainloop();
    }

    // Send and receive all messages
    connection->mainloop();
    if (!connection->doing_okay()) {
      shutDown();
    }

    // Handle forwarding requests;  send messages
    // on auxiliary connections
    forwarderServer->mainloop();

    // Sleep so we don't eat the CPU
#if defined(_WIN32)
    if (milli_sleep_time >= 0) {
#else
    if (milli_sleep_time > 0) {
#endif
      vrpn_SleepMsecs(milli_sleep_time);
    }
  }

  shutDown();
  return 0;
}
